/**
 *
 * @param {Number} x Abscisse de depart de l'objet
 * @param {Number} y Ordonnee de depart de l'objet
 */
function Position(x, y){
    // Definition des constantes (unit? en pixels)
    /**
     * Vitesse minimale d'un objet pour un calcul de vitesse aleatoire
     */
    this.VITESSE_MIN = 4;
    /**
     * Vitesse maximale d'un objet pour un calcul de vitesse aleatoire
     */
    this.VITESSE_MAX = 10;
    /**
     * Seuil que la cellule doit eviter de depasser pour approcher son
     * point d'arrivee
     */
    this.VITESSE_APPROCHE = 7;
    /**
     * Accelere la vitesse tant que la cellule n'a pas parcouru les n
     * premiers % indiques
     */
    this.ACCELERATION_JUSQU_A = 0.37;
    /**
     * Ralenti la vitesse des que la cellule a depasse les n% indiques
     * de la distance a parcourir
     */
    this.RALENTI_A_PARTIR_DE = 0.71;
    /**
     * Acceleration maximale d'un objet
     */
    this.VARIATION_VITESSE_MAX = 3;
    /**
     * Deplacement minimal d'un objet
     */
    this.DEPLACEMENT_MIN = 40;
    /**
     * Deplacement maximal d'un objet
     */
    this.DEPLACEMENT_MAX = 180;
    /**
     * Difference de deplacement d'un objet
     */
    this.DEPLACEMENT_MAX_MINUS_MIN = this.DEPLACEMENT_MAX - this.DEPLACEMENT_MIN;
    /**
     * Largeur maximale de la fenetre
     */
    this.LARGEUR_FRAME = 800;
    /**
     * Hauteur maximale de la fenetre
     */
    this.HAUTEUR_FRAME = 600;
    
    // Construction de l'objet
    /**
     * Abscisse de depart
     */
    this.xDepart = x;
    /**
     * Ordonnee de depart
     */
    this.yDepart = y;
    /**
     * Abscisse courante apres n deplacements
     */
    this.xActuel = x;
    /** 
     * Ordonnee courante apres n deplacements
     */
    this.yActuel = y;
    /** 
     * Abscisse de destination
     */
    this.xArrivee = -1;
    /**
     * Ordonnee de destination
     */
    this.yArrivee = -1;
    this.ancienneVitesse = 0;
    /**
     * Vitesse de l'objet : nombre de deplacements par tours.
     */
    this.vitesse = this.VITESSE_MIN + Math.round(Math.random() * (this.VITESSE_MAX - this.VITESSE_MIN));
    
    /**
     * L'invocation de cette methode permet de definir une nouvelle arrivee
     * s'il n'y en a plus (valeurs a -1 ou sup?rieure ? la taille de la frame),
     * et de calculer la prochaine position c'est a dire le couple xActuel et
     * yActuel.
     * La methode met aussi a jour la vitesse de l'objet en l'accelerant tant
     */
    this.seDeplace = function(){
        // Definition du point d'arrivee si necessaire
        if (this.xArrivee == this.xActuel && this.yArrivee == this.yActuel) {
            this.xArrivee = -1;
            this.yArrivee = -1;
        }
        if (this.xArrivee < 0 || this.yArrivee < 0 || this.xArrivee > this.LARGEUR_FRAME ||
        this.yArrivee > this.HAUTEUR_FRAME) {
            this.xDepart = this.xActuel;
            this.yDepart = this.yActuel;
            //TODO : Ameliorer le calcul de generation d'un nouveau point
            while (this.xArrivee < 0 || this.xArrivee > this.LARGEUR_FRAME) {
                if (Math.random() > 0.5) 
                    this.xArrivee = Math.round(this.xDepart + this.DEPLACEMENT_MIN +
                    (Math.random() * (this.DEPLACEMENT_MAX_MINUS_MIN)));
                else 
                    this.xArrivee = Math.round(this.xDepart - this.DEPLACEMENT_MIN -
                    (Math.random() * (this.DEPLACEMENT_MAX_MINUS_MIN)));
            }
            while (this.yArrivee < 0 || this.yArrivee > this.HAUTEUR_FRAME) {
                if (Math.random() > 0.5) 
                    this.yArrivee = Math.round(this.yDepart + this.DEPLACEMENT_MIN +
                    (Math.random() * (this.DEPLACEMENT_MAX_MINUS_MIN)));
                else 
                    this.yArrivee = Math.round(this.yDepart - this.DEPLACEMENT_MIN -
                    (Math.random() * (this.DEPLACEMENT_MAX_MINUS_MIN)));
            }
            this.recalculeVitesse(0);
        }
        
        // Ajustement de la vitesse de la cellule
        var dparcourue = (Math.abs(this.xArrivee - this.xActuel) + Math.abs(this.yArrivee - this.yActuel)) /
        (Math.abs(this.xArrivee - this.xDepart) + Math.abs(this.yArrivee - this.yDepart));
        if (this.ACCELERATION_JUSQU_A > dparcourue) 
            this.recalculeVitesse(1);
        else 
            if (this.RALENTI_A_PARTIR_DE < dparcourue && this.vitesse > this.VITESSE_APPROCHE) 
                this.recalculeVitesse(-1);
        
        // Calcul du prochain deplacement de la cellule avec mise a jour
        // des attributs de position actuelle
        if (this.vitesse >= Math.abs(this.xArrivee - this.xActuel) &&
        this.vitesse >= Math.abs(this.yArrivee - this.yActuel)) {
            this.xActuel = this.xArrivee;
            this.yActuel = this.yArrivee;
        }
        else {
            var ratio = Math.abs(this.xArrivee - this.xActuel) / Math.abs(this.yArrivee - this.yActuel);
            if (this.xDepart > this.xArrivee) 
                this.xActuel -= Math.round((ratio * this.vitesse));
            else 
                this.xActuel += Math.round((ratio * this.vitesse));
            if (this.yDepart > this.yArrivee) 
                this.yActuel -= Math.round(((1 - ratio) * this.vitesse));
            else 
                this.yActuel += Math.round(((1 - ratio) * this.vitesse));
        }
    };
    
    /**
     * Recalcule la vitesse en prenant en consideration le parametre changement
     * dont la valeur varie entre -1, 0 ou 1 signifiant une diminution ou
     * une augmentation de la vitesse, ou alors une demande de g?n?ration
     * aleatoire de vitesse
     *
     * La vitesse ne peut pas etre inferieure a 1 et n'a pas de maximum.
     *
     * La generation aleatoire d'une nouvelle vitesse se fait en fonction des
     * constantes declarees en debut de classe.
     *
     * On peut adoucir encore le mouvement en prenant mieux en consideration
     * deltav et en testant de maniere plus detaillee les valeurs qu'il prend
     *
     * @param {Number} changement -1 ou 0 ou 1 indiquant l'evolution de la vitesse
     */
    this.recalculeVitesse = function(changement){
        // variable permettant de conna?tre la tendance du mouvement
        var deltav = this.vitesse - this.ancienneVitesse;
        // Mise a jour de l'ancienne vitesse avec l'actuelle
        this.ancienneVitesse = this.vitesse;
        // Calcul de la nouvelle vitesse
        if (changement == -1) {
            /*
             * Si la cellule accelerait, la vitesse se stabilise. Sinon, si la
             * cellule se deplacait a vitesse constante, alors on diminue sa
             * vitesse de 1, sinon on la diminue entre 1 et la constante
             * de variation maximale de vitesse
             */
            if (deltav == 0) {
                if (this.vitesse > 1) 
                    this.vitesse--;
            }
            else 
                if (deltav < 0) 
                    if (this.vitesse > this.VARIATION_VITESSE_MAX) 
                        this.vitesse -= 1 + Math.round(Math.random() * (this.VARIATION_VITESSE_MAX - 1));
                    else 
                        if (this.vitesse > 1) 
                            this.vitesse--;
        }
        else {
            /*
             * Si la cellule ralentissait, la vitesse se stabilise. Sinon, si
             * la cellule se deplacait a vitesse constante, alors on augmente
             * de 1 sa vitesse, sinon on l'augmente entre 1 et la constante
             * de variation maximale de vitesse
             */
            if (changement == 1) {
                if (deltav == 0) {
                    this.vitesse++;
                }
                else 
                    if (deltav > 0) 
                        this.vitesse += 1 + Math.round(Math.random() * (this.VARIATION_VITESSE_MAX - 1));
            }
            else 
                if (changement == 0) 
                    this.vitesse = this.VITESSE_MIN + Math.round(Math.random() * (this.VITESSE_MAX - this.VITESSE_MIN));
        }
    };
    
    
    /**
     * Methode qui permet de definir une nouvelle destination pour la cellule
     * si celle-ci est arrivee a l'ancienne, ou si la methode a ete appellee
     * par la recherche de nourriture ou la fuite d'un ennemi.
     * La methode redefini le point de depart comme etant la position courante
     * de l'objet
     *
     * @param {Number} x Nouvelle abscisse de destination
     * @param {Number} y Nouvelle ordonnee de destination
     */
    this.changeDestination = function(xNouv, yNouv){
        if (xNouv != null && yNouv != null) {
            this.xDepart = this.xActuel;
            this.xArrivee = xNouv;
            this.yDepart = this.yActuel;
            this.yArrivee = yNouv;
        }
    };
    
    /**
     * Methode qui permet de se diriger a l'opposee des coordonnees passees
     * en parametre. Cela permet de fuir un ennmi. Si la cellule est dans un
     * coin, on ne change pas sa destination (piegee).
     *
     * @param {Object} xEnnemi Abscisse de l'ennemi a fuir
     * @param {Object} yEnnemi Ordonnee de l'ennemi a fuir
     */
    this.opposee = function(xEnnemi, yEnnemi){
        //TODO : à refaire : creer des téléportations et fait planter le programme
        /*var xTmp;
         var yTmp;
         var diffx = this.xActuel - xEnnemi;
         var diffy = this.yActuel - yEnnemi;
         if (diffx > 0)
         xTmp = this.xActuel + diffx;
         else
         xTmp = this.xActuel - diffx;
         if (diffy > 0)
         yTmp = this.yActuel + diffy;
         else
         yTmp = this.yActuel - diffy;
         
         if (xTmp < this.LARGEUR_FRAME && xTmp > 0)
         if (yTmp < this.HAUTEUR_FRAME && yTmp > 0)
         this.changeDestination(xTmp, yTmp);
         else
         this.changeDestination(xTmp, this.yActuel);
         else
         if (yTmp < this.HAUTEUR_FRAME && yTmp > 0)
         this.changeDestination(this.xActuel, yTmp);*/
    };
    
    /**
     * Permet de connaitre le xActuel de l'objet
     *
     * @return {Number} Abscisse courante de l'objet
     */
    this.getX = function(){
        return this.xActuel;
    };
    
    /**
     * Permet de connaitre le yActuel de l'objet
     *
     * @return {Number} Ordonnee courante de l'objet
     */
    this.getY = function(){
        return this.yActuel;
    };
    
    /**
     * Permet de savoir si la vitesse a ete modifiee ou non
     *
     * @type {Boolean}
     */
    this.vitesseNormale = true;
    /**
     * Methode qui permet de doubler la vitesse d'une cellule qui se
     * trouve dans un milieu ou la temperature est optimale
     * @param {Object} temperature
     */
    this.modifierVitesse = function(temperature){
        if (temperature == "up") {
            if (this.vitesseNormale) {
                this.VITESSE_MAX *= 2;
                this.VITESSE_APPROCHE *= 2;
                this.VITESSE_MIN *= 2;
                this.vitesseNormale = false;
            }
        }
        else {
            if (!this.vitesseNormale) {
                this.VITESSE_MAX /= 2;
                this.VITESSE_APPROCHE /= 2;
                this.VITESSE_MIN /= 2;
                this.vitesseNormale = true;
            }
        }
    };
}
